import http from 'http';
import https from 'https';
import sugar from '../../core/sugar';
import fs from 'fs'
import path from 'path';
import color from '../../utils/Color';
import { ctx, randerType } from '../../entrance/inter';
import Response from '../../interface/Response';
let type = global.loader(path.resolve(__dirname,'../../data/Content-Type.json'));

export = class ResponseModel implements Response{
    // 返回锁
    public ctx:ctx = null;
    public lock:boolean = false;
    public isClose:boolean = false;
    public set:boolean = true;
    
    constructor(ctx:ctx){
        this.ctx = ctx;
    }

    // 开启异步
    public startAsync(){
        this.lock = true;
    };

    // 读取渲染图片
    public sendFile(filepath:string,option:randerType={download:false,lock:true}):Promise<string>{
        // a如果为真代表使用返回，对返回数据进行锁定
        this.lock = option.lock;
        option.download===true && (this.lock = true)
        return new Promise(async (resolve,error)=>{
            try{
                //解析语法糖
                filepath = sugar.path(filepath,{superNumber:4});

                // 如果为真说明是需要下载的文件
                if(option.download){return resolve(await ResponseModel.download(filepath,this.ctx))}

                // 通过文件后缀获取文件的类型
                let filetype = type[path.extname(filepath)];
                
                //设置请求头
                if(filetype!==undefined && this.set){this.ctx.res.setHeader('Content-Type', filetype);}
                if(this.lock){
                    // 直接发送
                    let stream = fs.createReadStream(filepath)
                    stream.on("close",()=>{resolve("")});
                    stream.on("error",err=>{error(err)})
                    stream.pipe(this.ctx.res);
                }else{
                    this.ctx.$res.once("error",(err)=>{
                        if(err.message==="write after end"){
                            console.log(color("蓝色","Err: Response Stream Closed (response的写入流已经关闭)"))
                        }
                    })
                    let stream = fs.createReadStream(filepath);
                    stream.on("data",data=>this.ctx.$res.write(data))
                    stream.on("end",_=>resolve(""));
                    stream.on("error",err=>error(err));
                }
            }catch(err){
                console.log(err);
                error(err);
            }
        })
    };
    // 重定向
    public redirect(url:string) :void{
        this.ctx.res.writeHead(301,{Location: url});
    };

    public echo(data:any = ""){
        // 不允许再对res的请求头进行任何设置
        this.set = false;
        switch (typeof data){
            case "object":{
                try{
                    this.ctx.$res.write(JSON.stringify(data))
                }catch(err){
                    this.ctx.$res.write(String(data))
                }
                break;
            }
            default :{
                this.ctx.$res.write(String(data))
            }
        }
    };
    // 代理方法
    public proxy(url:string,option:any){
        this.lock=true;
        let req = (url.startsWith("https")?https:http).request(url,option,(res)=>res.pipe(this.ctx.$res))
        option.data && req.write(JSON.stringify(option.data));
        req.end();
    };

    // 返回数据 state代表是否需要判断锁
    public body(data:any="",state){
        // 如果被锁了 说明是异步返回不用提前结束
        try{
            if(!state || !this.lock){
                this.lock = true;
            }else return
            // 把异步结果等待出来
            switch (typeof data){
                case 'object':{
                try{
                    this.ctx.$res.end(JSON.stringify(data));
                }catch(Error){this.ctx.$res.end(String(data));}
                break;
                }
                default :{
                    // 不属于任何数据类型就有可能是空的
                    this.ctx.$res.end( String(data));
                }
            }
        }catch(e){
            console.log(e.message);
            console.log(e);
        }
    }

    // 下载文件
    static download(filepath:string,ctx:ctx) :Promise<string>{
        return new Promise(resolve=>{
            // 表示文件支持多线程下载
            ctx.res.setHeader("Accept-Ranges","bytes")
            // 获取文件的状态
            let state = fs.statSync(filepath);
            // 获取客户想获取的部分数据
            let range = this.Range(ctx.req.headers);
            // http://192.168.168.155:8088/%E6%B5%8B%E8%AF%95.txt?download=true
            if((!range.start || !range.end) || (range.end>state.size || range.start<0 || range.start>=range.end)){
                // 不符合规则直接返回全部文件
                range.start=0;
                range.end = state.size;
            }else{
                // 符合规则
                state.size = range.end - range.start;
            }
    
            ctx.res.setHeader('Content-Type', "application/octet-stream");
            // 获取文件名称 并转换为16进制
            let name:any = this.conversionUrl(Buffer.from(path.basename(filepath)).toString("hex"),2);
    
            ctx.res.setHeader('Content-Disposition', "attachment; filename="+name);
            ctx.res.setHeader('Content-Length', state.size);
            fs.createReadStream(filepath,{...range}).pipe(ctx.res).on("close",()=>resolve(""))
            return "";
        })
    }

    // 中文转16进制
    static conversionUrl(str:string,number:number){
        let data = "";
        for(let i=0;i<str.length;i+=number){
            data+="%"+str.substring(i,i+number);
        }
        return data;
    }

    // 解析出来文件需要下载的部分
    static Range(headers:any){
        let range:any = headers["range"]
        if(!range) return {start:0,end:0}
        // 存在就解析
        range = range.split(/bytes=|=/g).filter(e=>e)
        return {
            start:Number(range[0]) || 0,
            end: Number(range[1]) || 0
        }
    }

    static rander(filepath:string,option:randerType={download:false,lock:true},ctx:ctx) :Promise<string>{
        // a如果为真代表使用返回，对返回数据进行锁定
        ctx.response.lock = option.lock;
        option.download===true && (ctx.response.lock = true)
    
        return new Promise(async (resolve,error)=>{
            try{
                //解析语法糖
                filepath = sugar.path(filepath,{superNumber:4});
    
                // 如果为真说明是需要下载的文件
                if(option.download){return resolve(await this.download(filepath,ctx))}
    
                // 通过文件后缀获取文件的类型
                let filetype = type[path.extname(filepath)];
                
                //设置请求头
                if(filetype!==undefined && ctx.response.set){ctx.res.setHeader('Content-Type', filetype);}
                if(ctx.response.lock){
                    // 直接发送
                    let stream = fs.createReadStream(filepath)
                    stream.on("close",()=>{resolve("")});
                    stream.on("error",err=>{error(err)})
                    stream.pipe(ctx.res);
                }else{
                    ctx.$res.once("error",(err)=>{
                        if(err.message==="write after end"){
                            console.log(color("蓝色","Err: Response Stream Closed (response的写入流已经关闭)"))
                        }
                    })
                    let stream = fs.createReadStream(filepath);
                    stream.on("data",data=>ctx.$res.write(data))
                    stream.on("end",_=>resolve(""));
                    stream.on("error",err=>error(err));
                }
            }catch(err){
                console.log(err);
                error(err);
            }
        })
    }
}